#include "flash.h"

void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u32 NumToWrite);   

uint32_t UniqueSerialNumber;

// 用芯片唯一ID来做模块的MAC F0系列 0x1FFFF7AC  F1 系列 0x1FFFF7E8 G4系列 1FFF7590 F4 0x1FFF7A10
const uint32_t SerialNumber[3] = {0x1FFF7A10, 0x1FFF7A14, 0x1FFF7A18};

// 设备信息
DevBaseInfo DevInfoCur;
const DevBaseInfo  DevInfoInit = 
{
	1,                           //ServoID
	0,                           //AppUpgradeFlag;  舵机软件升级标志
	{0xD7,0x00,0x25,0x01},       //HardVersion(123)
	{0x02,0x22,0x11,0x09},       //SoftVerSion
	115200,                      //SciBaudRate
	1000000,                     //CanBaudRate
	0                            //check
};

const unsigned char DeviceInfo[7] =
{
    1, 0,    // VID 1
    20, 0,    // PID 20
    1, 0,    // 硬件版本
    'B'
};

uint32_t GetSector(uint32_t Address)
{
  uint32_t sector = 0;
  
  if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
  {
    sector = FLASH_Sector_0;  
  }
  else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
  {
    sector = FLASH_Sector_1;  
  }
  else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
  {
    sector = FLASH_Sector_2;  
  }
  else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
  {
    sector = FLASH_Sector_3;  
  }
  else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
  {
    sector = FLASH_Sector_4;  
  }
  else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
  {
    sector = FLASH_Sector_5;  
  }
  else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
  {
    sector = FLASH_Sector_6;  
  }
  else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
  {
    sector = FLASH_Sector_7;  
  }
  else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
  {
    sector = FLASH_Sector_8;  
  }
  else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
  {
    sector = FLASH_Sector_9;  
  }
  else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
  {
    sector = FLASH_Sector_10;  
  }
  else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))*/
  {
    sector = FLASH_Sector_11;  
  }

  return sector;
}


//*************************************************************************************************
// 函数名称:  FlashReadBuff
// 函数功能:  从FLASH中读指定长度数据
// 输入参数:  
// 	source_address		-	数据源地址
// 	buffer			-	用于保护读取结果的数据指针
// 	length			-	要读取的字节数
// 返回值:  无
//**************************************************************************************************
void FlashReadBuff(const uint32_t source_address,uint8_t *const buffer,uint16_t length)
{
	uint16_t i;
	uint8_t Offset = 0;
	uint32_t StartAddress = source_address;
	uint16_t data;
	
	// 地址检测
	if( source_address + length > FMC_FLASH_END ) return;
	
	// 如果没有对16齐
	if( source_address & 1 ) 
	{
		Offset = 1;
		StartAddress = source_address-1;
	}
	
	// flash的操作要求16对齐 最小读写操作16个比特
	if ( Offset )
	{
		data = *(uint16_t *)(StartAddress);
		buffer[0] = data >> 8;
		StartAddress += 2;
	}
	 
	for ( i = 0; i < (length-Offset); i += 2) 
	{
		data = *(uint16_t *)(StartAddress+i);
		buffer[i+Offset] = (data & 0xFF);
		if ( (i+Offset) < (length - 1) )
		 buffer[i + Offset + 1] = (data >> 8);
	}
	
}

//*************************************************************************************************
// 函数名称:  GetUniqueSN
// 函数功能:  得到芯片唯一码
// 输入参数:  无
// 返回值:    无
//**************************************************************************************************
void GetUniqueSN(void)
{
    uint32_t Temp = 0;
    uint8_t i;
    UniqueSerialNumber = 0;

    for (i = 0; i < 3; i++)
    {
        Temp = *(uint32_t *)(SerialNumber[i]);
        UniqueSerialNumber += Temp;
    }
}

//*************************************************************************************************
// 函数名称:  ReadDevInfo
// 函数功能:  从flash区下载设备信息，得到初始化信息
// 输入参数:  无
// 返回值  :  无
//**************************************************************************************************
void ReadDevInfo(void)
{
	uint16_t i;
	uint8_t Temp = 0;
	
	FlashReadBuff( DEVICE_INFO_ADDRESS,(uint8_t *)(&DevInfoCur),sizeof(DevBaseInfo) );
	for( i=0; i < sizeof(DevBaseInfo)-4; i++ )
		Temp += *( (uint8_t *)(&DevInfoCur)+i );
	
	// 数据不合法--更新数据
	if(  (DevInfoCur.check != Temp) ||  (DevInfoCur.ServoID == 0) ||  (DevInfoCur.ServoID == 0xff))
	{ 
		DevInfoCur = DevInfoInit;
	}
	
}

//*************************************************************************************************
// 函数名称:  UpdateDevInfo
// 函数功能:  更新设备信息到Flash区
// 输入参数:  无
// 返回值  :  无
//**************************************************************************************************
void UpdateDevInfo(void)
{
	uint16_t i;
	uint8_t Temp = 0;
	u32 secpos;	   //扇区地址   
    u32 offaddr;   //去掉0X08000000后的地址
	
	for( i = 0; i < sizeof(DevBaseInfo)-4; i++ )
		Temp += *( (uint8_t *)(&DevInfoCur) + i );
	
	DevInfoCur.check = Temp;

	i = GetSector(DEVICE_TAB_ADDRESS);
    TIM_Cmd(TIM6,DISABLE);
    FLASH_Unlock();
	FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_OPERR|FLASH_FLAG_WRPERR\
		            |FLASH_FLAG_PGAERR|FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
    FLASH_EraseSector(i,VoltageRange_3);
	FLASH_Lock();     
	STMFLASH_Write_NoCheck(DEVICE_INFO_ADDRESS,(uint16_t *)(&DevInfoCur),sizeof(DevBaseInfo)/2);	
	TIM_Cmd(TIM6,ENABLE);
}

//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
u16 STMFLASH_ReadHalfWord(u32 faddr)
{
    return *(vu16*)faddr; 
}


#if STM32_FLASH_WREN	//如果使能了写   
//不检查的写入
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数   
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u32 NumToWrite)   
{ 			 		 
    u16 i;
	
    for(i=0;i<NumToWrite;i++)
    {
        FLASH_Unlock();	
        FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
		FLASH_Lock();	
        WriteAddr+=2;//地址增加1.
    }  
} 

//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
u16 STMFLASH_BUF[FMC_SECTOR_SIZE/2];//最多是2K字节
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)	
{
    u32 secpos;	   //扇区地址
    u16 secoff;	   //扇区内偏移地址(16位字计算)
    u16 secremain; //扇区内剩余地址(16位字计算)	   
    u16 i;    
    u32 offaddr;   //去掉0X08000000后的地址
    
    if(WriteAddr<FMC_FLASH_BASE||(WriteAddr>=(FMC_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
    FLASH_Unlock();						    //解锁
    offaddr=WriteAddr-FMC_FLASH_BASE;	    //实际偏移地址.                       0x3004
    secpos=offaddr/FMC_SECTOR_SIZE;			//扇区地址  0~127 for STM32F103RBT6   0x3004/0x800 = 6  
    secoff=(offaddr%FMC_SECTOR_SIZE)/2;		//在扇区内的偏移(2个字节为基本单位.)  0x0002
    secremain=FMC_SECTOR_SIZE/2-secoff;		//扇区剩余空间大小                    0x03FE                                                     
    if(NumToWrite<=secremain) secremain=NumToWrite;//不大于该扇区范围            
    while(1) 
    {	
        STMFLASH_Read(secpos*FMC_SECTOR_SIZE+FMC_FLASH_BASE,STMFLASH_BUF,FMC_SECTOR_SIZE/2);//读出整个扇区的内容
        for(i=0;i<secremain;i++)//校验数据
        {
            if(STMFLASH_BUF[secoff+i]!=0XFFFF) break;//需要擦除  	  
        }
        if(i<secremain)//需要擦除
        {
            FLASH_EraseSector(secpos,VoltageRange_3);//擦除这个扇区
            for(i=0;i<secremain;i++)//复制
            {
                STMFLASH_BUF[i+secoff]=pBuffer[i];	  
            }
            STMFLASH_Write_NoCheck(secpos*FMC_SECTOR_SIZE+FMC_FLASH_BASE,STMFLASH_BUF,FMC_SECTOR_SIZE/2);//写入整个扇区  
        }
		else 
		{
            STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间. 
		}
						   
        if(NumToWrite==secremain) break;//写入结束了
        else//写入未结束
        {
            secpos++;				//扇区地址增1
            secoff=0;				//偏移位置为0 	 
            pBuffer+=secremain;  	//指针偏移
            WriteAddr+=secremain;	//写地址偏移	   
            NumToWrite-=secremain;	//字节(16位)数递减
            if(NumToWrite>(FMC_SECTOR_SIZE/2))secremain=FMC_SECTOR_SIZE/2;//下一个扇区还是写不完
            else secremain=NumToWrite;//下一个扇区可以写完了
        }	 
    };	
    FLASH_Lock();//上锁
}
#endif



//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)   	
{
    u16 i;
    for(i=0;i<NumToRead;i++)
    {
        pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
        ReadAddr+=2;//偏移2个字节.	
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
//WriteAddr:起始地址
//WriteData:要写入的数据
void Test_Write(u32 WriteAddr,u16 WriteData)   	
{
    STMFLASH_Write(WriteAddr,&WriteData,1);//写入一个字 
}
















